package com.ug.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ug.common.constant.CommonConstants;
import com.ug.common.enums.ErrorCode;
import com.ug.common.exception.SystemException;
import com.ug.common.id.SnowFlakeFactory;
import com.ug.common.utils.BeanUtils;
import com.ug.common.utils.SecurityUtil;
import com.ug.common.utils.StringUtil;
import com.ug.system.entity.SysMenu;
import com.ug.system.entity.SysRoleMenu;
import com.ug.system.entity.dto.SysMenuDto;
import com.ug.system.entity.vo.SysMenuTreeVO;
import com.ug.system.entity.vo.TreeSelectVO;
import com.ug.system.mapper.SysMenuMapper;
import com.ug.system.mapper.SysRoleMenuMapper;
import com.ug.system.service.SysMenuService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author LY
 * @create 2024/7/16 15:59
 * @Description 菜单服务实现层
 */
@Service
@RequiredArgsConstructor
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    private final SysRoleMenuMapper roleMenuMapper;

    @Override
    public List<SysMenuTreeVO> getMenuTree(List<String> roles) {
        List<SysMenu> menuListAll = sysMenuList(roles);
        return tree(menuListAll, 0L);
    }

    @Override
    public void editMenu(SysMenu sysMenu) {
        if (sysMenu.getParentId() == null){
            throw new SystemException(ErrorCode.DIRE_EDIT_ERROR);
        }
        if (sysMenu.getMenuId() != null){
            baseMapper.updateById(sysMenu);
        } else {
            sysMenu.setMenuId(SnowFlakeFactory.getSnowFlakeFromCache().nextId());
            baseMapper.insert(sysMenu);
        }
    }

    @Override
    public void delMenu(Long menuId) {
        //  校验菜单是否已绑定角色
        checkMenuRole(menuId);
        baseMapper.deleteById(menuId);
    }

    @Override
    public List<SysMenu> queryAllMenus(List<String> roles) {
        if (roles.contains(CommonConstants.ROLE_ADMIN)){
            return baseMapper.selectList(null);
        }
        return baseMapper.getMenuTree(roles);
    }

    @Override
    public List<SysMenuTreeVO> getMenuTable(SysMenuDto sysMenuDto) {
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        if (StringUtil.isNotBlank(sysMenuDto.getMenuName())){
            wrapper.like(SysMenu::getName, sysMenuDto.getMenuName());
        }
        if (StringUtil.isNotBlank(sysMenuDto.getMenuPath())){
            wrapper.like(SysMenu::getPath, sysMenuDto.getMenuName());
        }
        wrapper.orderByAsc(SysMenu::getSort);
        List<SysMenu> list = baseMapper.selectList(wrapper);
        return tree(list, 0L);
    }

    @Override
    public List<String> getUrlsByRoles(List<String> roles) {
        return baseMapper.getMenuUrlByRole(roles);
    }

    @Override
    public List<String> getPermission() {
        List<String> roles = SecurityUtil.getCurrentRoles();
        List<String> permissions;
        if (roles.contains(CommonConstants.ROLE_ADMIN)){
            LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(SysMenu::getPermission);
            wrapper.eq(SysMenu::getType, "3");
            permissions = baseMapper.selectObjs(wrapper).stream().map(o -> (String)o).collect(Collectors.toList());
        } else {
            permissions = baseMapper.getPermission(roles);
        }
        return permissions;
    }

    @Override
    public List<TreeSelectVO> getMenuTreeSelect() {
        return treeSelectVOList(sysMenuList(SecurityUtil.getCurrentRoles()), 0L);
    }

    /**
     * 获取下拉树
     * @param menus 菜单数据
     * @param root 跟节点
     * @return 目录树
     */
    private List<TreeSelectVO> treeSelectVOList(List<SysMenu> menus, Long root){
        Map<Long, List<TreeSelectVO>> parentMap = new HashMap<>();
        List<TreeSelectVO> list = new ArrayList<>();
        List<TreeSelectVO> trees = new ArrayList<>();
        for (SysMenu sm: menus){
            TreeSelectVO vo = new TreeSelectVO();
            vo.setValue(sm.getMenuId());
            vo.setLabel(sm.getName());
            list.add(vo);
            Long parentId = sm.getParentId();
            if (Objects.equals(parentId, root)){
                trees.add(vo);
                continue;
            }
            parentMap.computeIfAbsent(parentId, key -> new ArrayList<>()).add(vo);
        }
        for (TreeSelectVO menu: list){
            menu.setChildren(parentMap.get(menu.getValue()));
        }
        return trees;
    }

    /**
     * 校验菜单是否已绑定角色
     * @param menuId 菜单id
     */
    private void checkMenuRole(Long menuId){
        LambdaQueryWrapper<SysRoleMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysRoleMenu::getMenuId, menuId);
        long count = roleMenuMapper.selectCount(wrapper);
        if (count > 0){
            throw new SystemException(ErrorCode.MENU_BIND_ERROR);
        }
    }

    /**
     * 菜单树
     * @param menus 菜单数据
     * @param root 根节点
     * @return 树型数据
     */
    private List<SysMenuTreeVO> tree(List<SysMenu> menus, Long root){
        Map<Long, List<SysMenuTreeVO>> parentMap = new HashMap<>();
        List<SysMenuTreeVO> list = new ArrayList<>();
        List<SysMenuTreeVO> trees = new ArrayList<>();
        for (SysMenu sm: menus){
            SysMenuTreeVO vo = BeanUtils.copyProperties(sm, SysMenuTreeVO.class);
            list.add(vo);
            assert vo != null;
            Long parentId = vo.getParentId();
            if (Objects.equals(parentId, root)){
                trees.add(vo);
                continue;
            }
            parentMap.computeIfAbsent(parentId, key -> new ArrayList<>()).add(vo);
        }
        for (SysMenuTreeVO menu: list){
            menu.setChildren(parentMap.get(menu.getMenuId()));
        }
        return trees;
    }

    /**
     * 根据角色获取菜单
     * @param roles 用户角色
     */
    public List<SysMenu> sysMenuList(List<String> roles){
        List<SysMenu> menuListAll;
        //  如果角色中包含admin,则直接查询所有非按钮菜单
        if (roles.contains(CommonConstants.ROLE_ADMIN)){
            LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
            wrapper.ne(SysMenu::getType, "3");
            wrapper.orderByAsc(SysMenu::getSort);
            menuListAll = baseMapper.selectList(wrapper);
            //  否则
        } else {
            //  获取当前用户授权的菜单
            menuListAll = baseMapper.getMenuTree(roles);
            if (!CollectionUtils.isEmpty(menuListAll)){
                menuListAll = menuListAll.stream().filter(item -> !item.getType().equals("3")).collect(Collectors.toList());
            }
        }
        return menuListAll;
    }
}
